//----------------------------------Include-------------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mcu.h"
#include "glbvar.h"
#include "cloud.h"
//------------------------------------------------------------------------------
//global var defined in this file
#define  DTU_GLOBALS
#include "dtu.h"
//------------------------------------------------------------------------------

//启动信息
//^boot.rom
//AT command ready
//+SIM READY

//---------------------------------Global Var-----------------------------------
char      ga_imei[DTU_IMEI_LEN+1];     //imei--15位数字
uint32_t  gu32_local_ip;
uint8_t   gu8_csq;
//------------------------------------------------------------------------------

//-----------------------------------Macro--------------------------------------
#if 0
#define  RMT_IPv4                 "183.221.84.89"
#define  RMT_PORT                 50000
#else
#define  RMT_IPv4                 "115.236.153.174"       //test addr
#define  RMT_PORT                 10981
#endif
//------------------------------------------------------------------------------
//for rx
#define  RXBUF_LEN                (1024)
//------------------------------------------------------------------------------
//for tx
#define  _tx_data(p, l)           do{ mcu_uart1_dma_tx((char*)p, l); }while(0)
#define  TXBUF_LEN                (512)
//------------------------------------------------------------------------------
#define  RUN_IDLE                 0
#define  RUN_PWR_ON               1
#define  RUN_GET_ATOK             2
#define  RUN_PWR_OFF              3
#define  RUN_PWR_OFF_0            4
#define  RUN_PWR_OFF_1            5
#define  RUN_GET_IMEI             11
#define  RUN_GET_SIM              12
#define  RUN_GET_CSQ              13
#define  RUN_GET_CGATT            14
#define  RUN_GET_IP               20
#define  RUN_TCP_OPEN             21
#define  RUN_ACTIVE               22
//------------------------------------------------------------------------------

//------------------------------------Type--------------------------------------
typedef struct{
  unsigned int   cnt;
  unsigned int   done;
  char           data[RXBUF_LEN];
}t_rcv;
//------------------------------------------------------------------------------

//---------------------------------Static Var-----------------------------------
//for rx
static t_rcv            nt_rcv;
static char             nrxbuf[RXBUF_LEN];
//for rx data proc
static uint32_t         nu32_rxlen;
static char             nrxdata[RXBUF_LEN];
//for tx
static char             ntxbuf[TXBUF_LEN];
//------------------------------------------------------------------------------
static uint32_t         nu32_rs         = RUN_IDLE;
static uint64_t         nu64_time_tick  = 0;
//------------------------------------------------------------------------------
static char             nsbuf[TXBUF_LEN];
static uint32_t         nu32_timeout = 0;
static uint32_t         nu32_error = 0;
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
static void _dtu_tx(char* s)
{
  strcpy(ntxbuf, s);
  _tx_data(ntxbuf, strlen(ntxbuf));
}
//------------------------------------------------------------------------------
static char* _check_rx(uint32_t* sz)
{
  *sz = 0;
  if(!nt_rcv.done) return NULL;
  if(!nt_rcv.cnt ) return NULL;
  *sz = nt_rcv.cnt;
  if(nt_rcv.cnt >= RXBUF_LEN) nt_rcv.data[RXBUF_LEN-1] = 0;
  else                        nt_rcv.data[nt_rcv.cnt]  = 0;
  return &nt_rcv.data[0];
}

static void _clear_rx(void)
{
  nt_rcv.done = 0;
  nt_rcv.cnt  = 0;
}
//------------------------------------------------------------------------------
//just like:
//+CGSN: 867145060012759\r\n\r\nOK
static uint32_t _get_imei(char* pbuf, uint32_t sz, char* imei)
{
  char* p;
  int   i;
  p  = pbuf;
  p  = strstr(p, "+CGSN: ");  if(!p) return 1;
  p += strlen("+CGSN: ");
  //imei
  for(i=0; i<DTU_IMEI_LEN; i++){ imei[i] = p[i]; }
  imei[DTU_IMEI_LEN] = 0;
  return 0;
}

//just like:
//+CSQ: 22,99
static uint32_t _get_csq(char* pbuf, uint32_t sz, uint8_t* csq)
{
  char* p;
  int   v;
  p  = pbuf;
  p  = strstr(p, "+CSQ:");  if(!p) return 1;
  p += strlen("+CSQ:");
  //csq
  v = atoi(p);  *csq = v;
  return 0;
}

//just like:
//+MIPCALL: 100.86.27.150
static uint32_t _get_ip(char* pbuf, uint32_t* ip)
{
  char* p;
  int   v;
  p  = pbuf;
  p  = strstr(p, "+MIPCALL:");  if(!p) return 1;
  p += strlen("+MIPCALL:");
  //ip
  p = strchr(p, ' ');  if(!p) return 2;  p = p+1;  v = atoi(p);  *ip = v<<24;
  p = strchr(p, '.');  if(!p) return 3;  p = p+1;  v = atoi(p);  *ip = *ip + (v<<16);
  p = strchr(p, '.');  if(!p) return 4;  p = p+1;  v = atoi(p);  *ip = *ip + (v<<8);
  p = strchr(p, '.');  if(!p) return 5;  p = p+1;  v = atoi(p);  *ip = *ip + (v);
  return 0;
}
//------------------------------------------------------------------------------
static uint8_t _ascii_to_hex(char d)
{
  uint8_t  r=0;
  if     ( (d >= '0') && (d <= '9') ){ r = d - 0x30;     }    //0x30--0x39
  else if( (d >= 'a') && (d <= 'z') ){ r = d - 0x61 +10; }    //0x61--0x66
  else if( (d >= 'A') && (d <= 'Z') ){ r = d - 0x41 +10; }    //0x41--0x46
  return r;
}
static uint8_t _ascii_to_byte(char* s)
{
  return (_ascii_to_hex(s[0])<<4) + _ascii_to_hex(s[1]);
}
//just like:
//+MIPRTCP: 1,0,313233
static uint32_t _cvt_recv(char* pbuf, uint32_t sz)
{
  char* p;
  char* pd;
  p  = pbuf;
  p  = strstr(p, "+MIPRTCP:");  if(!p) return 1;
  p += strlen("+MIPRTCP:");
  //search
  p = strchr(p, ',');  if(!p) return 2;  p=p+1;
  p = strchr(p, ',');  if(!p) return 2;  p=p+1;
  //data
  pd = strchr(p, '\r');  if(!p) return 3;
  if( !(pd>=p+2) ) return 4;
  
  nu32_rxlen = (pd-p)/2;
  for(uint32_t i=0; i<nu32_rxlen; i++){
    nrxdata[i] = _ascii_to_byte(p);
    p+=2;
  }
  return 0;
}
//------------------------------------------------------------------------------
static char*     p;
static uint32_t  sz;
static uint32_t  s_retry;
static void _cyc_proc(void)
{
  switch(nu32_rs){
  case RUN_IDLE:
    if(igu64_tick_ms > nu64_time_tick + 2000){    //time out
      _dtu_tx("AT\r\n");
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_GET_ATOK;
    }
    break;
  case RUN_GET_ATOK:
    if(igu64_tick_ms > nu64_time_tick + 1000){    //time out
      nu64_time_tick = igu64_tick_ms;
      if(++s_retry >= 3){
        s_retry = 0;
        mcu_dtu_pwr_key(0);
        nu32_rs = RUN_PWR_ON;
      }else{
        nu32_rs = RUN_IDLE;
      }
      break;
    }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "OK")){
      _dtu_tx("AT+CGSN=1\r\n");
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_GET_IMEI;
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;
  case RUN_PWR_ON:
    if(igu64_tick_ms > nu64_time_tick + 1000){    //time out
      mcu_dtu_pwr_key(1);
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_IDLE;
    }
    break;
  //--------------------------------------------
  case RUN_PWR_OFF:
    mcu_dtu_pwr_key(0);
    nu64_time_tick = igu64_tick_ms;
    nu32_rs = RUN_PWR_OFF_0;
    break;
  case RUN_PWR_OFF_0:
    if(igu64_tick_ms > nu64_time_tick + 4*1000){
      mcu_dtu_pwr_key(1);
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_PWR_OFF_1;
    }
    break;
  case RUN_PWR_OFF_1:
    if(igu64_tick_ms > nu64_time_tick + 6*1000){
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_IDLE;
      nu32_timeout = 0;
      nu32_error = 0;
    }
    break;
  //--------------------------------------------
  case RUN_GET_IMEI:{
    if(igu64_tick_ms > nu64_time_tick + 5*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }else if(strstr(p, "+CGSN:")){    //xxxxx
      if( _get_imei(p, sz, ga_imei) == 0 ){
        _dtu_tx("AT+CPIN?\r\n");
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_GET_SIM;
      }else{
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_IDLE;
      }
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_GET_SIM:{
    if(igu64_tick_ms > nu64_time_tick + 5*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "+CPIN: READY")){
      _dtu_tx("AT+CSQ\r\n");
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_GET_CSQ;
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_GET_CSQ:{
    if(igu64_tick_ms > nu64_time_tick +10*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "AT+CSQ")){    //+CSQ: 19,0
      if( _get_csq(p, sz, &gu8_csq) == 0 ){
        _dtu_tx("AT+CGATT?\r\n");
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_GET_CGATT;
      }else{
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_IDLE;
      }
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_GET_CGATT:{
    if(igu64_tick_ms > nu64_time_tick +10*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "+CGATT: 1")){
      if(gu32_local_ip){
        sprintf(nsbuf, "AT+MIPOPEN=1,,\"%s\",%d,0\r\n", RMT_IPv4, RMT_PORT);
        _dtu_tx(nsbuf);
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_TCP_OPEN;
      }else{
        _dtu_tx("AT+MIPCALL=1,\"CMNET\"\r\n");
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_GET_IP;
      }
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_GET_IP:{
    if(igu64_tick_ms > nu64_time_tick +10*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "+MIPCALL:")){
      if( _get_ip(p, &gu32_local_ip) == 0 ){
        sprintf(nsbuf, "AT+MIPOPEN=1,,\"%s\",%d,0\r\n", RMT_IPv4, RMT_PORT);
        _dtu_tx(nsbuf);
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_TCP_OPEN;
      }else{
        nu64_time_tick = igu64_tick_ms;
        nu32_rs = RUN_IDLE;
      }
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_TCP_OPEN:{
    if(igu64_tick_ms > nu64_time_tick +10*1000){ nu64_time_tick = igu64_tick_ms; if(++nu32_timeout >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE; break; }
    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "+MIPOPEN: 1,1")){
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_ACTIVE;
      nu32_timeout = 0;
    }else if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }
    _clear_rx();
    break;}
  //--------------------------------------------
  case RUN_ACTIVE:
    cloud_cyc();

    p = _check_rx(&sz);  if(!p) break;
    if(strstr(p, "ERROR")){
      nu64_time_tick = igu64_tick_ms;
      if(++nu32_error >= 20) nu32_rs = RUN_PWR_OFF; else nu32_rs = RUN_IDLE;
    }else if(strstr(p, "closed")){
      nu64_time_tick = igu64_tick_ms;
      nu32_rs = RUN_IDLE;
    }else if(strstr(p, "+MIPRTCP:")){
      if( _cvt_recv(p, sz) == 0){
        cloud_parse(nrxdata, nu32_rxlen);
      }
    }
    _clear_rx();
    break;
    
  default: break;
  }
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
//just like:
//AT+MIPSEND=1,"313233"  --write to buffer (2048B)
//AT+MIPPUSH=1           --real send
void dtu_wr_buf(char* p, uint32_t len)
{
  if(len == 0) return;
  nsbuf[0] = 0;
  for(uint32_t i=0; i<len; i++){
    sprintf(ntxbuf, "%02x", p[i]);
    strcat(nsbuf, ntxbuf);
  }
  sprintf(ntxbuf, "AT+MIPSEND=1,\"%s\"\r\n", nsbuf);
  _dtu_tx(ntxbuf);
}

void dtu_push(void)
{
  _dtu_tx("AT+MIPPUSH=1\r\n");
}
//------------------------------------------------------------------------------
//for DMA receive
uint32_t dtu_get_rcv_addr(void)
{
  return (uint32_t)&nrxbuf[0];
}

uint32_t dtu_get_rcv_size(void)
{
  return RXBUF_LEN;
}

void it_dtu_dma_rcv_done(uint32_t cnt)
{
  if(cnt){
    memcpy(&nt_rcv.data[0], &nrxbuf[0], cnt);
    nt_rcv.cnt  = cnt;
    nt_rcv.done = 1;
  }
}
//------------------------------------------------------------------------------
void dtu_pwr_off(void)
{
  mcu_dtu_pwr_key(0);
  mcu_delay_ms(4000);   //硬件关机--拉低 PWRKEY 至少 3.1 秒
  mcu_dtu_pwr_key(1);
  mcu_delay_ms(6000);   // >=5s
}

void dtu_cyc(void)
{
  _cyc_proc();
}
//-------------------------------------EOF--------------------------------------







